
class StateMachine {
    variable = {}

    stateActions = {}

    conditions = {}

    lastStateName = ""
    currentStateName = ""

    setCurrentStateName(currentStateName){
        this.lastStateName = this.currentStateName
        this.currentStateName = currentStateName
    }

    addState(stateName, action){
        this.stateActions[stateName] = action
    }

    setVariable(stateName, value){
        const oldValue = this.variable[stateName]
        this.variable[stateName] = value
        this.atatusDetection( stateName , value, oldValue)
    }

    getVariable(stateName){
        return this.variable[stateName]
    }
    
    addCondition(currentStateName, nextStateName, condition, re_condition){
        this.conditions[currentStateName] ||( this.conditions[currentStateName] = {} )
        this.conditions[nextStateName] ||( this.conditions[nextStateName] = {} )

        this.conditions[currentStateName][nextStateName] = condition

        re_condition && ( this.conditions[nextStateName][currentStateName] = re_condition )
    }

    atatusDetection(stateName, value, oldValue){
        const conditions = this.conditions[this.currentStateName]

        if(conditions){
            const keys = Object.keys(conditions)
            for (let i = 0; i < keys.length; i++) {
                if(conditions[ keys[i] ](this.variable, {
                    stateName, value, oldValue,
                    stateActionName: keys[i]
                })){
                    this.setCurrentStateName( keys[i] )
                    break
                }
            }
        }
    }

    invoke(userData={}){
        this.stateActions[this.currentStateName] && this.stateActions[this.currentStateName](this.variable,{
            userData,
            lastStateName: this.lastStateName
        })
    }
}

const stateMachine = new StateMachine()

stateMachine.addState("idle", () => {
    stateMachine.setVariable("speed", 10)
    console.log("idle")
})
stateMachine.addState("walk", (_, {lastStateName}) => {
    if(lastStateName === "run"){
        stateMachine.setVariable("speed", 0)
    }
    else{
        stateMachine.setVariable("speed", 20)
    }
    console.log("walk")
})
stateMachine.addState("run", () => {
    stateMachine.setVariable("speed", 0)
    console.log("run")
})

stateMachine.addCondition("idle", "walk", ({speed})=> speed > 0, ({speed})=> speed === 0)
stateMachine.addCondition("walk", "run", ({speed})=> speed >= 20, ({speed})=> speed < 20)

stateMachine.setVariable("speed", 0)
stateMachine.setCurrentStateName("idle")
setInterval(()=> stateMachine.invoke(), 1000)